package com.suning.sawp.service.util;

import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 新人红包领取接口 custNum 所用加密算法
 * @author 14062606
 *
 */
public class PBECoder {
	/**
     * 采用的加密算法
     */
    public static final String ALGORITHM = "PBEWITHMD5andDES";

    /**
     * 默认盐，可配置，需要与客户端保持一致 盐的位数必须为8字字节
     */
    public static final String DEFAULTSALT = "sn201209";

    /**
     * 默认盐，可配置，需要与客户端保持一致 盐的位数必须为8字字节
     */
    public static final byte[] salt = DEFAULTSALT.getBytes();
    /**
     * 密钥摘要次数，可配置，需要与客户端保持一致
     */
    public static final int ITERATIONSNUM = 50;

    private static final Logger LOGGER = LoggerFactory.getLogger(PBECoder.class);

    /**
     * 转换密钥<br>
     * 
     * @param password 口令，这里暂定为用户名
     * @return
     * @throws NoSuchAlgorithmException 
     * @throws InvalidKeySpecException 
     * @throws Exception
     */
    private static Key toKey(String password) throws NoSuchAlgorithmException, InvalidKeySpecException {
        PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());

        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);

        SecretKey secretKey = keyFactory.generateSecret(keySpec);

        return secretKey;
    }

    /**
     * 加密
     * 
     * @param data 数据
     * @param password 密码
     * @param salt 盐
     * @return
     * @throws InvalidKeySpecException 
     * @throws NoSuchAlgorithmException 
     * @throws NoSuchPaddingException 
     * @throws InvalidAlgorithmParameterException 
     * @throws InvalidKeyException 
     * @throws BadPaddingException 
     * @throws IllegalBlockSizeException 
     * @throws Exception
     */
    public static byte[] encrypt(byte[] data, String password, byte[] salt) throws NoSuchAlgorithmException,
            InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException,
            IllegalBlockSizeException, BadPaddingException {

        Key key = toKey(password);

        PBEParameterSpec paramSpec = new PBEParameterSpec(salt, 50);
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);

        return cipher.doFinal(data);

    }

    /**
     * 解密
     * 
     * @param data 数据
     * @param password 密码
     * @param salt 盐
     * @return
     * @throws InvalidKeySpecException 
     * @throws NoSuchAlgorithmException 
     * @throws NoSuchPaddingException 
     * @throws InvalidAlgorithmParameterException 
     * @throws InvalidKeyException 
     * @throws BadPaddingException 
     * @throws IllegalBlockSizeException 
     * @throws Exception
     */
    public static String decrypt(String hex, String password) throws NoSuchAlgorithmException, InvalidKeySpecException,
            NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException,
            BadPaddingException {

        byte[] data = hex2byte(hex);

        Key key = toKey(password);

        PBEParameterSpec paramSpec = new PBEParameterSpec(salt, 50);
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, key, paramSpec);

        return new String(cipher.doFinal(data));

    }

    /**
     * 把密文解密之后，转成请求参数的键值对
     * 
     * @param hex 密文
     * @param password 干扰串
     * @return 请求参数键值对
     * @throws BadPaddingException 
     * @throws IllegalBlockSizeException 
     * @throws InvalidAlgorithmParameterException 
     * @throws NoSuchPaddingException 
     * @throws InvalidKeySpecException 
     * @throws NoSuchAlgorithmException 
     * @throws InvalidKeyException 
     * @throws Exception
     */
    public static Map<String, String> decryptAndConvertToMap(String hex, String password) throws InvalidKeyException,
            NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException,
            InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
        String queryStr = decrypt(hex, password);
        return convertQueryStringToMap(queryStr);
    }

    /**
     * 把请求参数转成键值对
     * 
     * @param queryStr 请求参数
     * @return 请求参数键值对
     */
    private static Map<String, String> convertQueryStringToMap(String queryStr) {

        Map<String, String> requestParams = new HashMap<String, String>();

        if (StringUtils.isEmpty(queryStr)) {
            return requestParams;
        }
        String key, value;
        int len;
        if (queryStr.indexOf("&") > -1) {
            String[] nvps = queryStr.split("&");
            for (int i = 0; i < nvps.length; i++) {
                len = nvps[i].indexOf("=");
                if (len > -1) {
                    key = nvps[i].substring(0, len);
                    value = nvps[i].substring(len + 1, nvps[i].length());
                    requestParams.put(key, value.replace("<>", "&"));
                }
            }
        } else {
            len = queryStr.indexOf("=");
            if (len > -1) {
                key = queryStr.substring(0, len);
                value = queryStr.substring(len + 1, queryStr.length());
                requestParams.put(key, value.replace("<>", "&"));
            }
        }
        return requestParams;
    }

    /**
     * 二行制转十六进制字符串
     * 
     * @param b
     * @return
     */
    public static String byte2hex(byte[] b) {
        StringBuffer hs = new StringBuffer("");
        String stmp = "";

        for (int n = 0; n < b.length; n++) {
            // 整数转成十六进制表示
            stmp = java.lang.Integer.toHexString(b[n] & 0XFF);

            if (stmp.length() == 1) {
                hs.append("0" + stmp);
            } else {
                hs.append(stmp);
            }
        }

        return hs.toString().toUpperCase(); // 转成大写
    }

    /**
     * 十六进制字符串转二行制
     * 
     * @param str
     * @return
     * @throws ECApplicationException
     */
    public static byte[] hex2byte(String str) {
        if (str == null) {
            return null;
        }

        str = str.trim();
        int len = str.length();
        if (len == 0 || len % 2 != 0) {
            return null;
        }

        byte[] b = new byte[len / 2];

        try {
            for (int i = 0; i < str.length(); i += 2) {
                b[i / 2] = (byte) Integer.decode("0x" + str.substring(i, i + 2)).intValue();
            }

            return b;
        } catch (Exception e) {
            LOGGER.error("PBECoder hex2byte error.", e);
            return null;
        }
    }
}
